// Copyright 2014 PDFium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
 
// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com

#ifndef TTGSUBTable_H
#define TTGSUBTable_H
#include "../../fx_freetype.h"
#include "../../../include/fxcrt/fx_basic.h"
#include "common.h"
class CFX_GlyphMap
{
public:
    CFX_GlyphMap();
    ~CFX_GlyphMap();
    void	SetAt(int key, int value);
    FX_BOOL	Lookup(int key, int &value);
protected:
    CFX_BinaryBuf	m_Buffer;
};
class CFX_CTTGSUBTable : public CFX_Object
{
public:
    CFX_CTTGSUBTable(void): m_bFeautureMapLoad(FALSE), loaded(false) {};
    CFX_CTTGSUBTable(FT_Bytes gsub): m_bFeautureMapLoad(FALSE), loaded(false)
    {
        LoadGSUBTable(gsub);
    }
    virtual ~CFX_CTTGSUBTable() {}
    bool IsOk(void) const
    {
        return loaded;
    }
    bool LoadGSUBTable(FT_Bytes gsub);
    bool GetVerticalGlyph(TT_uint32_t glyphnum, TT_uint32_t *vglyphnum);
private:
    struct tt_gsub_header {
        TT_uint32_t Version;
        TT_uint16_t ScriptList;
        TT_uint16_t FeatureList;
        TT_uint16_t LookupList;
    };
    struct TLangSys {
        TT_uint16_t LookupOrder;
        TT_uint16_t ReqFeatureIndex;
        TT_uint16_t FeatureCount;
        TT_uint16_t *FeatureIndex;
        TLangSys(): LookupOrder(0), ReqFeatureIndex(0), FeatureCount(0), FeatureIndex(NULL) {}
        ~TLangSys()
        {
            if(FeatureIndex) {
                delete[] FeatureIndex;
            }
        }
    private:
        TLangSys(const TLangSys&);
        TLangSys& operator=(const TLangSys&);
    };
    struct TLangSysRecord {
        TT_uint32_t LangSysTag;
        struct TLangSys LangSys;
        TLangSysRecord(): LangSysTag(0) {}
    private:
        TLangSysRecord(const TLangSysRecord&);
        TLangSysRecord& operator=(const TLangSysRecord&);
    };
    struct TScript {
        TT_uint16_t DefaultLangSys;
        TT_uint16_t LangSysCount;
        struct TLangSysRecord *LangSysRecord;
        TScript(): DefaultLangSys(0), LangSysCount(0), LangSysRecord(NULL) {}
        ~TScript()
        {
            if(LangSysRecord) {
                delete[] LangSysRecord;
            }
        }
    private:
        TScript(const TScript&);
        TScript& operator=(const TScript&);
    };
    struct TScriptRecord {
        TT_uint32_t ScriptTag;
        struct TScript Script;
        TScriptRecord(): ScriptTag(0) {}
    private:
        TScriptRecord(const TScriptRecord&);
        TScriptRecord& operator=(const TScriptRecord&);
    };
    struct TScriptList {
        TT_uint16_t ScriptCount;
        struct TScriptRecord *ScriptRecord;
        TScriptList(): ScriptCount(0), ScriptRecord(NULL) {}
        ~TScriptList()
        {
            if(ScriptRecord) {
                delete[] ScriptRecord;
            }
        }
    private:
        TScriptList(const TScriptList&);
        TScriptList& operator=(const TScriptList&);
    };
    struct TFeature {
        TT_uint16_t FeatureParams;
        int LookupCount;
        TT_uint16_t *LookupListIndex;
        TFeature(): FeatureParams(0), LookupCount(0), LookupListIndex(NULL) {}
        ~TFeature()
        {
            if(LookupListIndex) {
                delete[] LookupListIndex;
            }
        }
    private:
        TFeature(const TFeature&);
        TFeature& operator=(const TFeature&);
    };
    struct TFeatureRecord {
        TT_uint32_t FeatureTag;
        struct TFeature Feature;
        TFeatureRecord(): FeatureTag(0) {}
    private:
        TFeatureRecord(const TFeatureRecord&);
        TFeatureRecord& operator=(const TFeatureRecord&);
    };
    struct TFeatureList {
        int FeatureCount;
        struct TFeatureRecord *FeatureRecord;
        TFeatureList(): FeatureCount(0), FeatureRecord(NULL) {}
        ~TFeatureList()
        {
            if(FeatureRecord) {
                delete[] FeatureRecord;
            }
        }
    private:
        TFeatureList(const TFeatureList&);
        TFeatureList& operator=(const TFeatureList&);
    };
    enum TLookupFlag {
        LOOKUPFLAG_RightToLeft = 0x0001,
        LOOKUPFLAG_IgnoreBaseGlyphs = 0x0002,
        LOOKUPFLAG_IgnoreLigatures = 0x0004,
        LOOKUPFLAG_IgnoreMarks = 0x0008,
        LOOKUPFLAG_Reserved = 0x00F0,
        LOOKUPFLAG_MarkAttachmentType = 0xFF00,
    };
    struct TCoverageFormatBase {
        TT_uint16_t CoverageFormat;
        CFX_GlyphMap m_glyphMap;
        TCoverageFormatBase(): CoverageFormat(0) {}
        virtual ~TCoverageFormatBase() {}
    private:
        TCoverageFormatBase(const TCoverageFormatBase&);
        TCoverageFormatBase& operator=(const TCoverageFormatBase&);
    };
    struct TCoverageFormat1: public TCoverageFormatBase {
        TT_uint16_t GlyphCount;
        TT_uint16_t *GlyphArray;
        TCoverageFormat1(): GlyphCount(0), GlyphArray(NULL)
        {
            CoverageFormat = 1;
        }
        ~TCoverageFormat1()
        {
            if(GlyphArray) {
                delete[] GlyphArray;
            }
        }
    private:
        TCoverageFormat1(const TCoverageFormat1&);
        TCoverageFormat1& operator=(const TCoverageFormat1&);
    };
    struct TRangeRecord {
        TT_uint16_t Start;
        TT_uint16_t End;
        TT_uint16_t StartCoverageIndex;
        TRangeRecord(): Start(0), End(0), StartCoverageIndex(0) {}
        friend bool operator > (const TRangeRecord &r1, const TRangeRecord &r2)
        {
            return r1.Start > r2.Start;
        }
    private:
        TRangeRecord(const TRangeRecord&);
    };
    struct TCoverageFormat2: public TCoverageFormatBase {
        TT_uint16_t RangeCount;
        struct TRangeRecord *RangeRecord;
        TCoverageFormat2(): RangeCount(0), RangeRecord(NULL)
        {
            CoverageFormat = 2;
        }
        ~TCoverageFormat2()
        {
            if(RangeRecord) {
                delete[] RangeRecord;
            }
        }
    private:
        TCoverageFormat2(const TCoverageFormat2&);
        TCoverageFormat2& operator=(const TCoverageFormat2&);
    };
    struct TClassDefFormatBase {
        TT_uint16_t ClassFormat;
        TClassDefFormatBase(): ClassFormat(0) {}
        virtual ~TClassDefFormatBase() {}
    private:
        TClassDefFormatBase(const TClassDefFormatBase&);
        TClassDefFormatBase& operator=(const TClassDefFormatBase&);
    };
    struct TClassDefFormat1: public TClassDefFormatBase {
        TT_uint16_t StartGlyph;
        TT_uint16_t GlyphCount;
        TT_uint16_t *ClassValueArray;
        TClassDefFormat1(): StartGlyph(0), GlyphCount(0), ClassValueArray(NULL)
        {
            ClassFormat = 1;
        }
        ~TClassDefFormat1()
        {
            if(ClassValueArray) {
                delete[] ClassValueArray;
            }
        }
    private:
        TClassDefFormat1(const TClassDefFormat1&);
        TClassDefFormat1& operator=(const TClassDefFormat1&);
    };
    struct TClassRangeRecord {
        TT_uint16_t Start;
        TT_uint16_t End;
        TT_uint16_t Class;
        TClassRangeRecord(): Start(0), End(0), Class(0) {}
    private:
        TClassRangeRecord(const TClassRangeRecord&);
        TClassRangeRecord& operator=(const TClassRangeRecord&);
    };
    struct TClassDefFormat2: public TClassDefFormatBase {
        TT_uint16_t ClassRangeCount;
        struct TClassRangeRecord *ClassRangeRecord;
        TClassDefFormat2(): ClassRangeCount(0), ClassRangeRecord(NULL)
        {
            ClassFormat = 2;
        }
        ~TClassDefFormat2()
        {
            if(ClassRangeRecord) {
                delete[] ClassRangeRecord;
            }
        }
    private:
        TClassDefFormat2(const TClassDefFormat2&);
        TClassDefFormat2& operator=(const TClassDefFormat2&);
    };
    struct TDevice {
        TT_uint16_t StartSize;
        TT_uint16_t EndSize;
        TT_uint16_t DeltaFormat;
        TDevice(): StartSize(0), EndSize(0), DeltaFormat(0) {}
    private:
        TDevice(const TDevice&);
        TDevice& operator=(const TDevice&);
    };
    struct TSubTableBase {
        TT_uint16_t SubstFormat;
        TSubTableBase(): SubstFormat(0) {}
        virtual ~TSubTableBase() {}
    private:
        TSubTableBase(const TSubTableBase&);
        TSubTableBase& operator=(const TSubTableBase&);
    };
    struct TSingleSubstFormat1: public TSubTableBase {
        TCoverageFormatBase *Coverage;
        TT_int16_t DeltaGlyphID;
        TSingleSubstFormat1(): Coverage(NULL), DeltaGlyphID(0)
        {
            SubstFormat = 1;
        }
        ~TSingleSubstFormat1()
        {
            if(Coverage) {
                delete Coverage;
            }
        }
    private:
        TSingleSubstFormat1(const TSingleSubstFormat1&);
        TSingleSubstFormat1& operator=(const TSingleSubstFormat1&);
    };
    struct TSingleSubstFormat2: public TSubTableBase {
        TCoverageFormatBase *Coverage;
        TT_uint16_t GlyphCount;
        TT_uint16_t *Substitute;
        TSingleSubstFormat2(): Coverage(NULL), GlyphCount(0), Substitute(NULL)
        {
            SubstFormat = 2;
        }
        ~TSingleSubstFormat2()
        {
            if(Coverage) {
                delete Coverage;
            }
            if(Substitute) {
                delete[] Substitute;
            }
        }
    private:
        TSingleSubstFormat2(const TSingleSubstFormat2&);
        TSingleSubstFormat2& operator=(const TSingleSubstFormat2&);
    };
    struct TLookup {
        TT_uint16_t LookupType;
        TT_uint16_t LookupFlag;
        TT_uint16_t SubTableCount;
        struct TSubTableBase **SubTable;
        TLookup(): LookupType(0), LookupFlag(0), SubTableCount(0), SubTable(NULL) {}
        ~TLookup()
        {
            if(SubTableCount > 0 && SubTable != NULL) {
                for(int i = 0; i < SubTableCount; i++) {
                    delete SubTable[i];
                }
                delete[] SubTable;
            }
        }
    private:
        TLookup(const TLookup&);
        TLookup& operator=(const TLookup&);
    };
    struct TLookupList {
        int LookupCount;
        struct TLookup *Lookup;
        TLookupList(): LookupCount(0), Lookup(NULL) {}
        ~TLookupList()
        {
            if(Lookup) {
                delete[] Lookup;
            }
        }
    private:
        TLookupList(const TLookupList&);
        TLookupList& operator=(const TLookupList&);
    };
    bool Parse(
        FT_Bytes scriptlist,
        FT_Bytes featurelist,
        FT_Bytes lookuplist);
    void ParseScriptList(FT_Bytes raw, TScriptList *rec);
    void ParseScript(FT_Bytes raw, TScript *rec);
    void ParseLangSys(FT_Bytes raw, TLangSys *rec);
    void ParseFeatureList(FT_Bytes raw, TFeatureList *rec);
    void ParseFeature(FT_Bytes raw, TFeature *rec);
    void ParseLookupList(FT_Bytes raw, TLookupList *rec);
    void ParseLookup(FT_Bytes raw, TLookup *rec);
    void ParseCoverage(FT_Bytes raw, TCoverageFormatBase **rec);
    void ParseCoverageFormat1(FT_Bytes raw, TCoverageFormat1 *rec);
    void ParseCoverageFormat2(FT_Bytes raw, TCoverageFormat2 *rec);
    void ParseSingleSubst(FT_Bytes raw, TSubTableBase **rec);
    void ParseSingleSubstFormat1(FT_Bytes raw, TSingleSubstFormat1 *rec);
    void ParseSingleSubstFormat2(FT_Bytes raw, TSingleSubstFormat2 *rec);
    bool GetVerticalGlyphSub(
        TT_uint32_t glyphnum,
        TT_uint32_t *vglyphnum,
        struct TFeature *Feature);
    bool GetVerticalGlyphSub2(
        TT_uint32_t glyphnum,
        TT_uint32_t *vglyphnum,
        struct TLookup *Lookup);
    int GetCoverageIndex(struct TCoverageFormatBase *Coverage, TT_uint32_t g);
    TT_uint8_t GetUInt8(FT_Bytes& p) const
    {
        TT_uint8_t ret = p[0];
        p += 1;
        return ret;
    }
    TT_int16_t GetInt16(FT_Bytes& p) const
    {
        TT_uint16_t ret = p[0] << 8 | p[1];
        p += 2;
        return *(TT_int16_t*)&ret;
    }
    TT_uint16_t GetUInt16(FT_Bytes& p) const
    {
        TT_uint16_t ret = p[0] << 8 | p[1];
        p += 2;
        return ret;
    }
    TT_int32_t GetInt32(FT_Bytes& p) const
    {
        TT_uint32_t ret = p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3];
        p += 4;
        return *(TT_int32_t*)&ret;
    }
    TT_uint32_t GetUInt32(FT_Bytes& p) const
    {
        TT_uint32_t ret = p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3];
        p += 4;
        return ret;
    }
    CFX_CMapDWordToDWord m_featureMap;
    FX_BOOL	m_bFeautureMapLoad;
    bool loaded;
    struct tt_gsub_header header;
    struct TScriptList ScriptList;
    struct TFeatureList FeatureList;
    struct TLookupList LookupList;
};
class CFX_GSUBTable FX_FINAL : public IFX_GSUBTable, public CFX_Object
{
public:
    virtual void	Release() FX_OVERRIDE
    {
        delete this;
    }
    virtual FX_BOOL GetVerticalGlyph(FX_DWORD glyphnum, FX_DWORD* vglyphnum) FX_OVERRIDE;
    CFX_CTTGSUBTable m_GsubImp;
};
#endif
